package wiiusej.apptest;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import wiiusej.WiiUseApiManager;
import wiiusej.Wiimote;
import wiiusej.apptest.statistics.SimResult;
import wiiusej.wiiusejevents.physicalevents.MotionSensingEvent;
import wiiusej.wiiusejevents.physicalevents.WiimoteButtonsEvent;
import wiiusej.wiiusejevents.utils.WiimoteBasicListener;
import wiiusej.wiiusejevents.wiiuseapievents.DisconnectionEvent;
import wiiusej.wiiusejevents.wiiuseapievents.StatusEvent;
import wiiusej.wiiusejevents.wiiuseapievents.WiiUseApiEvent;

public class WiimoteNetListener implements Runnable{

	
	private static Logger fileLogger;
	//private static Object[] myWiimotes = new ArrayList<Object>();
	
	//producer-consumer queue for Connection/WiimoteNetListener COM
	private static BlockingQueue<ArrayList<Long>> toConnection = 
		new LinkedBlockingQueue<ArrayList<Long>>();
	
	private static ArrayList<SimResult> simResults;
	
	//Sim parameters
	private static int simulationLength; //packets per simulation
	private static int timeout; //milliseconds
	
	BlockingQueue<WiiUseApiEvent> fromPostmant;
	WiiUseApiManager manager;
	
	private static HashMap<Integer, Wiimote> myWiimotes;	
	private ArrayList<Long> timeStats = new ArrayList<Long>();
	
	private long lastRefNumber = 0;
	private int sendCounter = 0;
	
	//Simulation parameters
	private static int simLength; 
	private static short initTimeout; 
	private static int netTimeout = 5;
	private static int packetCounter = 0;
	
	private static ArrayList<Long> delayResults = new ArrayList<Long>();
	
	
	//Sim results
	private static HashMap<Long, SimResult> mapResults;
	
	public WiimoteNetListener(WiiUseApiManager manager, BlockingQueue<WiiUseApiEvent> fromPostman, 
			HashMap<Integer, Wiimote> wiimotes, BlockingQueue<ArrayList<Long>> fromNetListener, 
			String[] simParameters, HashMap<Long, SimResult> mapResults){		
			
		this.fromPostmant = fromPostman;
		this.manager = manager;
		this.myWiimotes = wiimotes;
				
		this.toConnection = fromNetListener; 
		
		this.simLength = Integer.parseInt(simParameters[1]);
		this.initTimeout = (short) Integer.parseInt(simParameters[2]);
		this.mapResults = mapResults;

		
		PropertyConfigurator.configure("log4j.properties");
		this.fileLogger = Logger.getLogger("netListener");
		
		Set set = wiimotes.keySet();	
		fileLogger.info("Wiimotes: " + set.toString());
		//fileLogger.info("");		
		
		if(!delayResults.isEmpty()){
			delayResults.clear();
		}
	}
	
	public void run(){				
		
		fileLogger.info("SimLentgh: " + simLength + " Lastnumber: " + lastRefNumber);
		 			
		SimpleDateFormat tsFormat = new SimpleDateFormat("mm:ss:SS");
		packetCounter = 0;
		
		fileLogger.info("PacketCounter: " + packetCounter);
		boolean running = true; 
		
		while(simLength > packetCounter && running==true){
			
			sendCounter++;
			
			fileLogger.info("**************************************************");
			Timestamp ts1 = new Timestamp (System.currentTimeMillis());
			fileLogger.info("Requesting Status " + tsFormat.format(ts1) + " sendCounter: " + sendCounter );
			
			//Send Wiimote Status Request
			sendStatusPacket();
							
			try {				
				//it is possible that the communication falls down. So, we wait at most 10 seconds.				
				WiiUseApiEvent evt = (WiiUseApiEvent) fromPostmant.poll(netTimeout, TimeUnit.SECONDS);
				
				if(evt == null){
					running = false;
					fileLogger.info("NULL elemeent retreived. Running: " + running);						
				}else{					
					Timestamp ts2 = new Timestamp (System.currentTimeMillis());
					fileLogger.info("Response from Wiimote " + tsFormat.format(ts2) + " refNumber: " + evt.getRefNumber());
					delayCalc(ts1, ts2);					
				}								
			} catch (InterruptedException e) {
				e.printStackTrace();				
				fileLogger.info("Timeout: " + netTimeout + " expired");
			}			
			
			packetCounter++;
		}			
		
		
		//send the results to Connection
		fileLogger.info("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		fileLogger.info("Sending Sim Results to Connection");
		fileLogger.info("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		
		
		try {
			toConnection.put(delayResults);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}	
	
	
	private void delayCalc(Timestamp ts1, Timestamp ts2) {		
		Long delay = ts2.getTime() - ts1.getTime();
		delayResults.add(delay);		
		fileLogger.info(delay);				
	}

	private void sendStatusPacket() {		
		/*
		Set s=wiimotes.keySet();  
		Iterator i=s.iterator();  
		while(i.hasNext)  
		S.o.p(i.next());*/
		
		//fileLogger.info("...Sending Status Packet...");
		manager.getStatus(1);
		
		/*
		Set set = myWiimotes.keySet();		
		Iterator it = set.iterator();
		
		Integer id = 0; 
		
		for(int i = 0; i<1; i++){			
			id = (Integer) it.next();			
		}
		
		if(!myWiimotes.isEmpty()){		
			manager.getStatus(11);			
		}else{
			fileLogger.info("WARNING: There are no Wiimotes!!");
		}*/
	}

//	public ArrayList<Integer> getMyWiimotes() {
//		return myWiimotes;
//	}
//
//	public void setMyWiimotes(ArrayList<Integer> myWiimotes) {
//		this.myWiimotes = myWiimotes;
//	}
//	
//	
//	public void addMyWiimotes(Integer id) {
//		this.myWiimotes.add(id);
//	}

	

	

	
}
